// TributeStipulation.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Collections;
using System.Collections.Generic;

using Supremacy.Economy;
using Supremacy.Entities;
using Supremacy.Game;
using Supremacy.Orbitals;
using Supremacy.Resources;
using Supremacy.Universe;
using System.Text;

namespace Supremacy.Diplomacy
{
    [Serializable]
    public abstract class TreatyStipulation : Stipulation
    {
        public TreatyStipulation()
        {
            this.DurationInternal = IndefiniteDuration;
        }

        public sealed override bool IsDurationFixed
        {
            get { return true; }
        }

        public sealed override bool IsMutual
        {
            get { return true; }
        }

        public sealed override int MinDuration
        {
            get { return DurationStepSize; }
        }
    }

    [Serializable]
    public abstract class ThirdPartyStipulation : Stipulation
    {
        public ThirdPartyStipulation()
        {
            this.DurationInternal = ImmediateDuration;
        }

        public sealed override bool IsDurationFixed
        {
            get { return true; }
        }

        public override Type ParameterType
        {
            get { return typeof(Civilization); }
        }

        public Civilization ThirdParty
        {
            get { return this.Parameter as Civilization; }
            set { this.Parameter = value; }
        }

        public override bool IsParameterValid
        {
            get { return (this.ThirdParty != null);}
        }

        public override object Parameter
        {
            get
            {
                string civKey = base.Parameter as string;
                if (civKey != null)
                    return GameContext.Current.Civilizations[civKey];
                return null;
            }
            set
            {
                Civilization civ = value as Civilization;
                base.Parameter = (civ != null) ? civ.Key : null;
            }
        }

        protected override IList GetParameterListOverride(DiplomacyContext context)
        {
            List<Civilization> targets = new List<Civilization>();
            foreach (Civilization otherCiv in GameContext.Current.Civilizations)
            {
                if ((otherCiv != context.InitiatingParty) && (otherCiv != context.OtherParty))
                {
                    if (DiplomacyHelper.IsContactMade(context.InitiatingParty, otherCiv)
                        && DiplomacyHelper.IsContactMade(context.OtherParty, otherCiv))
                    {
                        targets.Add(otherCiv);
                    }
                }
            }
            return targets;
        }
    }

    [Serializable]
    public sealed class GiftDetails
    {
        #region Fields
        private readonly ResourceValueCollection _resources;
        private int _credits;
        #endregion

        #region Constructors
        public GiftDetails()
        {
            _resources = new ResourceValueCollection();
        }
        #endregion

        #region Properties
        public int Credits
        {
            get { return _credits; }
            set { _credits = value; }
        }

        public ResourceValueCollection Resources
        {
            get { return _resources; }
        }

        public string Description
        {
            get
            {
                List<string> items = new List<string>();
                StringBuilder result = new StringBuilder();
                if (this.Credits > 0)
                {
                    items.Add(String.Format("{0} Credits", this.Credits));
                }
                foreach (ResourceType resource in Enum.GetValues(typeof(ResourceType)))
                {
                    if (this.Resources[resource] > 0)
                    {
                        items.Add(
                            String.Format(
                                "{0} {1}",
                                this.Resources[resource],
                                GameContext.Current.Tables.EnumTables[typeof(ResourceType).Name][resource.ToString()][0]));
                    }
                }
                if (items.Count > 0)
                {
                    for (int i = 0; i < items.Count; i++)
                    {
                        if (i > 0)
                        {
                            result.Append((items.Count > 2) ? ", " : " ");
                            if (i == (items.Count - 1))
                            {
                                result.Append("and ");
                            }
                        }
                        result.Append(items[i]);
                    }
                }
                return result.ToString();
            }
        }
        #endregion

        public override string ToString()
        {
            return this.Description;
        }
    }

    [Serializable]
    public sealed class GiftStipulation : Stipulation
    {
        #region Constructors
        public GiftStipulation()
        {
            Parameter = new GiftDetails();
        }
        #endregion

        #region Properties
        public GiftDetails GiftDetails
        {
            get { return (GiftDetails)Parameter; }
        }

        public override string ShortDescription
        {
            get { return ResourceManager.GetString("STIPULATION_NAME_TRIBUTE"); }
        }

        public override CivString LongDescription
        {
            get { return new CivString(CivString.DiplomacyCategory, "STIPULATION_DESC_TRIBUTE"); }
        }

        public override bool IsParameterValid
        {
            get
            {
                if (GiftDetails.Credits > 0)
                    return true;
                foreach (ResourceType resource in Enum.GetValues(typeof(ResourceType)))
                {
                    if (GiftDetails.Resources[resource] > 0)
                        return true;
                }
                return false;
            }
        }

        public override Type ParameterType
        {
            get { return typeof(GiftDetails); }
        }
        #endregion

        #region Methods
        protected override void ExecuteOverride(DiplomacyContext context)
        {
            CivilizationManager sender = GameContext.Current.CivilizationManagers[context.InitiatingParty];
            CivilizationManager recipient = GameContext.Current.CivilizationManagers[context.OtherParty];

            if (this.GiftDetails.Credits > 0)
            {
                int change = sender.Credits.AdjustCurrent(-1 * this.GiftDetails.Credits);
                if (change > 0)
                    recipient.Credits.AdjustCurrent(change);
            }

            foreach (ResourceType resource in Enum.GetValues(typeof(ResourceType)))
            {
                if (this.GiftDetails.Resources[resource] > 0)
                {
                    int change = sender.Resources[resource].AdjustCurrent(
                        -1 * this.GiftDetails.Resources[resource]);
                    if (change > 0)
                        recipient.Resources[resource].AdjustCurrent(change);
                }
            }
        }
        #endregion
    }

    [Serializable]
    public sealed class NonAggressionPactStipulation : TreatyStipulation
    {
        #region Constructors
        public NonAggressionPactStipulation()
        {
            this.Effects |= StipulationEffect.CloseBorders;
        }
        #endregion

        #region Properties
        public override string ShortDescription
        {
            get { return ResourceManager.GetString("STIPULATION_NAME_NON_AGGRESSION_PACT"); }
        }

        public override CivString LongDescription
        {
            get { return new CivString(CivString.DiplomacyCategory, "STIPULATION_DESC_NON_AGGRESSION_PACT"); }
        }
        #endregion

        #region Methods
        protected override void ApplyOverride(DiplomacyContext context)
        {
            foreach (Fleet fleet in GameContext.Current.Universe.FindOwned<Fleet>(context.InitiatingParty))
            {
                if (GameContext.Current.SectorClaims.IsClaimedByCiv(fleet.Location, context.OtherParty))
                {
                    fleet.SetRouteInternal(TravelRoute.Empty);
                    fleet.Location = MapHelper.FindNearestFriendlySector(fleet);
                }
            }
            foreach (Fleet fleet in GameContext.Current.Universe.FindOwned<Fleet>(context.OtherParty))
            {
                if (GameContext.Current.SectorClaims.IsClaimedByCiv(fleet.Location, context.InitiatingParty))
                {
                    fleet.SetRouteInternal(TravelRoute.Empty);
                    fleet.Location = MapHelper.FindNearestFriendlySector(fleet);
                }
            }
        }
        #endregion
    }

    [Serializable]
    public class TradeAgreementStipulation : TreatyStipulation
    {
        #region Constructors
        public TradeAgreementStipulation()
        {
            this.Effects |= StipulationEffect.AllowTrade;
        }
        #endregion

        #region Properties
        public override string ShortDescription
        {
            get { return ResourceManager.GetString("STIPULATION_NAME_TRADE_AGREEMENT"); }
        }

        public override CivString LongDescription
        {
            get { return new CivString(CivString.DiplomacyCategory, "STIPULATION_DESC_TRADE_AGREEMENT"); }
        }
        #endregion
    }

    [Serializable]
    public sealed class OpenBordersStipulation : TradeAgreementStipulation
    {
        #region Constructors
        public OpenBordersStipulation()
        {
            this.Effects |= StipulationEffect.GrantShipPassage;
        }
        #endregion

        #region Properties
        public override string ShortDescription
        {
            get { return ResourceManager.GetString("STIPULATION_NAME_OPEN_BORDERS"); }
        }

        public override CivString LongDescription
        {
            get { return new CivString(CivString.DiplomacyCategory, "STIPULATION_DESC_OPEN_BORDERS"); }
        }
        #endregion
    }

    [Serializable]
    public sealed class AllianceStipulation : TreatyStipulation
    {
        #region Constructors
        public AllianceStipulation()
        {
            this.Effects |= StipulationEffect.AllowTrade;
            this.Effects |= StipulationEffect.GrantShipPassage;
            this.Effects |= StipulationEffect.DefensiveAidRequired;
            this.Effects |= StipulationEffect.GrantRepairRights;
            this.Effects |= StipulationEffect.ShareIntel;
            this.Effects |= StipulationEffect.ShareSupplies;
        }
        #endregion

        #region Properties
        public override string ShortDescription
        {
            get { return ResourceManager.GetString("STIPULATION_NAME_ALLIANCE"); }
        }

        public override CivString LongDescription
        {
            get { return new CivString(CivString.DiplomacyCategory, "STIPULATION_DESC_ALLIANCE"); }
        }
        #endregion
    }

    [Serializable]
    public sealed class MembershipStipulation : TreatyStipulation
    {
        private List<int> _colonies;

        #region Constructors
        public MembershipStipulation()
        {
            _colonies = null;

            this.Effects |= StipulationEffect.AllowTrade;
            this.Effects |= StipulationEffect.GrantShipPassage;
            this.Effects |= StipulationEffect.DefensiveAidRequired;
            this.Effects |= StipulationEffect.GrantRepairRights;
            this.Effects |= StipulationEffect.ShareIntel;
            this.Effects |= StipulationEffect.ShareSupplies;
            this.Effects |= StipulationEffect.MembershipGranted;
        }
        #endregion

        #region Properties
        public override string ShortDescription
        {
            get { return ResourceManager.GetString("STIPULATION_NAME_MEMBERSHIP"); }
        }

        public override CivString LongDescription
        {
            get { return new CivString(CivString.DiplomacyCategory, "STIPULATION_DESC_MEMBERSHIP"); }
        }
        #endregion

        protected override void ApplyOverride(DiplomacyContext context)
        {
            base.ApplyOverride(context);
            var empire = context.InitiatingParty.IsEmpire
                ? context.InitiatingParty
                : context.OtherParty;
            var member = context.InitiatingParty.IsEmpire
                ? context.OtherParty
                : context.InitiatingParty;
            var colonies = GameContext.Current.Universe.FindOwned<Colony>(member);
            _colonies = new List<int>();
            foreach (var colony in colonies)
            {
                colony.OwnerID = empire.CivID;
                _colonies.Add(colony.ObjectID);
                if (GameContext.Current.CivilizationManagers[member] != null)
                    GameContext.Current.CivilizationManagers[member].Colonies.Remove(colony);
                if (GameContext.Current.CivilizationManagers[empire] != null)
                    GameContext.Current.CivilizationManagers[empire].Colonies.Add(colony);
            }
        }

        protected override void TerminateOverride(TerminationContext context)
        {
            base.TerminateOverride(context);
            if (_colonies != null)
            {
                var empire = context.Agreement.Sender.IsEmpire
                   ? context.Agreement.Sender
                   : context.Agreement.Recipient;
                var member = context.Agreement.Sender.IsEmpire
                   ? context.Agreement.Recipient
                   : context.Agreement.Sender;
                for (int i = 0; i < _colonies.Count; i++)
                {
                    var colony = GameContext.Current.Universe.Objects[_colonies[i]] as Colony;
                    if (colony != null)
                    {
                        colony.Owner = member;
                        if (GameContext.Current.CivilizationManagers[empire] != null)
                            GameContext.Current.CivilizationManagers[empire].Colonies.Remove(colony);
                        if (GameContext.Current.CivilizationManagers[member] != null)
                            GameContext.Current.CivilizationManagers[member].Colonies.Add(colony);
                    }
                }
            }
        }
    }

    [Serializable]
    public sealed class DeclareWarStipulation : ThirdPartyStipulation
    {
        #region Properties
        public override string ShortDescription
        {
            get { return ResourceManager.GetString("STIPULATION_NAME_DECLARE_WAR"); }
        }

        public override CivString LongDescription
        {
            get { return new CivString(CivString.DiplomacyCategory, "STIPULATION_DESC_DECLARE_WAR"); }
        }
        #endregion

        #region Methods
        protected override bool CanExecuteOverride(DiplomacyContext context)
        {
            Civilization thisCiv = context.IsDemand ? context.OtherParty : context.InitiatingParty;
            if (this.ThirdParty != null)
            {
                Relationship relationship = GameContext.Current.Relationships[thisCiv, this.ThirdParty];
                if (relationship != null)
                {
                    return !relationship.AtWar;
                }
            }
            return false;
        }

        protected override void ExecuteOverride(DiplomacyContext context)
        {
            Civilization thisCiv = context.IsDemand ? context.OtherParty : context.InitiatingParty;
            if (this.ThirdParty != null)
            {
                Relationship relationship = GameContext.Current.Relationships[thisCiv, this.ThirdParty];
                if ((relationship != null) && (!relationship.AtWar))
                {
                    relationship.DeclareWar();
                }
            }
        }

        protected override IList GetParameterListOverride(DiplomacyContext context)
        {
            IList targets = base.GetParameterListOverride(context);
            Civilization thisCiv = context.IsDemand ? context.OtherParty : context.InitiatingParty;
            for (int i = 0; i < targets.Count; i++)
            {
                Relationship relationship = GameContext.Current.Relationships[thisCiv, (Civilization)targets[i]];
                if (relationship.AtWar || relationship.Allied)
                {
                    targets.RemoveAt(i--);
                }
            }
            return targets;
        }
        #endregion
    }

    [Serializable]
    public sealed class TerminateAgreementsStipulation : ThirdPartyStipulation
    {
        #region Properties
        public override string ShortDescription
        {
            get { return ResourceManager.GetString("STIPULATION_NAME_TERMINATE_AGREEMENTS"); }
        }

        public override CivString LongDescription
        {
            get { return new CivString(CivString.DiplomacyCategory, "STIPULATION_DESC_TERMINATE_AGREEMENTS"); }
        }

        public override Type ParameterType
        {
            get { return typeof(Civilization); }
        }
        #endregion

        #region Methods
        protected override bool CanExecuteOverride(DiplomacyContext context)
        {
            Civilization thisCiv = context.IsDemand ? context.OtherParty : context.InitiatingParty;
            if (this.ThirdParty != null)
            {
                Relationship relationship = GameContext.Current.Relationships[thisCiv, this.ThirdParty];
                if (relationship != null)
                {
                    return (relationship.ActiveAgreements.Count > 0);
                }
            }
            return false;
        }

        protected override void ExecuteOverride(DiplomacyContext context)
        {
            Civilization thisCiv = context.IsDemand ? context.OtherParty : context.InitiatingParty;
            if (this.ThirdParty != null)
            {
                Relationship relationship = GameContext.Current.Relationships[thisCiv, this.ThirdParty];
                if ((relationship != null) && (!relationship.AtWar))
                {
                    relationship.DeclareWar();
                }
            }
        }

        protected override IList GetParameterListOverride(DiplomacyContext context)
        {
            IList targets = base.GetParameterListOverride(context);
            Civilization thisCiv = context.IsDemand ? context.OtherParty : context.InitiatingParty;
            for (int i = 0; i < targets.Count; i++)
            {
                Relationship relationship = GameContext.Current.Relationships[thisCiv, (Civilization)targets[i]];
                if (relationship.ActiveAgreements.Count == 0)
                {
                    targets.RemoveAt(i--);
                }
            }
            return targets;
        }
        #endregion
    }
}